package com.caishi.lkx.exam.api;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.caishi.lkx.common.AdminBaseApi;
import com.caishi.lkx.common.config.DiamondConfig;
import com.caishi.lkx.common.role.Roles;
import com.caishi.lkx.exam.model.*;
import com.caishi.lkx.exam.service.*;
import com.caishi.lkx.exam.vo.MyNoteRelationVO;
import com.caishi.lkx.exam.vo.MyNoteVO;
import com.caishi.lkx.exam.vo.QuestionVo;
import com.caishi.lkx.user.model.IUserModel;
import com.caishi.lkx.user.model.UserModel;
import com.caishi.lkx.user.service.IUserService;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.impl.BSDAbsEntity;
import com.zzw.common.entity.impl.BSDUAbsEntity;
import com.zzw.common.entity.impl.BaseAbsEntity;
import com.zzw.common.entity.impl.BaseEntity;

import com.caishi.lkx.exam.ienum.status.NoteVerifyStatus;
import com.caishi.lkx.exam.ienum.type.PaperType;
import com.caishi.lkx.exam.ienum.type.QuestionCollectionType;
import com.caishi.lkx.exam.ienum.type.QuestionSourceType;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author by liyihua
 * @date : 2022-04-01 11:01
 */
@Tag(name = "笔记相关")
@Slf4j
@RestController
@RequestMapping("/exam/note")
public class NoteApi extends AdminBaseApi<INoteService, NoteModel, String> {

    @Resource
    private INoteService noteService;
    @Resource
    private IQuestionService questionService;
    @Resource
    private IChapterService chapterService;
    @Resource
    private IPaperService paperService;
    @Resource
    private IUserService userService;
    @Resource
    private IPaperRecordsService paperRecordsService;
    @Resource
    private IEveryDayPracticeService everyDayPracticeService;
    @Resource
    private ICategoryService categoryService;
    @Resource
    private IExamService examService;
    @Resource
    private IIndustryService industryService;

    @Resource
    private DiamondConfig diamondConfig;

    @Override
    public INoteService loadService() {
        return noteService;
    }

    @Override
    protected List<NoteModel> listCover(List<NoteModel> result, JSONObject otherParam) {
        result.parallelStream().forEach(r -> {
            UserModel userModel = (UserModel) userService.getById(r.getModifyBy());
            if (null != userModel) {
                r.setModifyBy(userModel.getName());
            }

            switch (r.getType()) {
                case chapter:
                    ChapterModel chapterModel = chapterService.getById(r.getRelationId());
                    r.setRelationName(chapterModel != null ? chapterModel.getName() : null);
                    break;
                case paper:
                    PaperModel paperModel = paperService.getById(r.getRelationId());
                    if (ObjectUtil.isNotEmpty(paperModel)) {

                        r.setRelationName(paperModel != null ? paperModel.getName() : null);
                    } else {
                        PaperRecordsModel paperRecordsModel = paperRecordsService.getById(r.getRelationId());
                        if (null != paperRecordsModel) {
//                            PaperModel paperInfo = paperService.getPaperInfo(paperRecordsModel.getPaperId());
//                            r.setRelationName(paperInfo != null ? paperInfo.getName() : null);
                            r.setRelationName(paperRecordsModel.getName());
                        }
                    }
                    break;
                default:
                    CategoryModel model = categoryService.getById(Long.valueOf(r.getCategoryId()));
                    r.setRelationName(industryService.queryName(model.getIndustryId()) + "-" + examService.queryName(model.getExamId()) + "-" + model.getName());
                    break;
            }
        });
        return super.listCover(result, otherParam);
    }

    @Operation(summary = "发表笔记")
    @PostMapping("/update")
    public NoteModel add(@RequestBody NoteModel entity) {
        if (!entity.getOpen()) {
            entity.setVerify(NoteVerifyStatus.pass.getCode());
        }
        return loadService().insert(entity);
    }

    @PutMapping("/update")
    public NoteModel update(@RequestBody NoteModel entity) {
        NoteModel noteModel = this.loadService().getById(entity.getId());
        if (entity.getOpen() && noteModel.getVerify().equals(3)) {
            entity.setVerify(0);
        }
        return loadService().simpleUpdate(entity);
    }

    @GetMapping("my-note")
    @Operation(summary = "我的笔记")
    @Parameters({
            @Parameter(name = "type", required = false, description = "chapter章节,paper试卷, 其他的传rankError"),
            @Parameter(name = "newFlag", description = "是否最新笔记,则不用传type"),
            @Parameter(name = "categoryId", description = "科目id")
    })
    public Object myNote(@RequestParam(required = false) QuestionCollectionType type, @RequestParam Boolean newFlag, @RequestParam Long categoryId,
                         @ModelAttribute Page<NoteModel> page) {
        LambdaQueryWrapper<NoteModel> wrapper = Wrappers.<NoteModel>lambdaQuery().eq(NoteModel::getCategoryId, categoryId)
                .eq(BSDUAbsEntity::getCreatedBy, userContext.currentUserId());
        if (newFlag) {
            IPage<NoteModel> newPage = new Page<>();
            BeanUtil.copyProperties(page, newPage);
            newPage = noteService.page(page, wrapper.orderByDesc(BSDAbsEntity::getCreatedTime));
            List<NoteModel> record = newPage.getRecords().parallelStream().peek(n -> {
                QuestionModel questionModel = questionService.getById(n.getQuestionId());
                if (questionModel.getSourceType().equals(QuestionSourceType.combination)) {
                    n.setQuestionId(questionModel.getSourceId());
                }
                n.setStem(questionModel.getStem());
            }).collect(Collectors.toList());
            newPage.setRecords(record);
            return newPage;
        } else {
            //章节 跟 试卷
            if (QuestionCollectionType.chapter == type || QuestionCollectionType.paper == type) {
                wrapper.eq(NoteModel::getType, type);
            } else {
                wrapper.ne(NoteModel::getType, QuestionCollectionType.chapter).ne(NoteModel::getType, QuestionCollectionType.paper);
            }
            wrapper.orderByDesc(NoteModel::getCreatedTime);
            List<NoteModel> noteModels = noteService.selectList(wrapper);
            Map<String, List<NoteModel>> map = noteModels.stream().sorted(Comparator.comparing(NoteModel::getCreatedTime, Comparator.nullsLast(Comparator.reverseOrder()))).collect(Collectors.groupingBy(NoteModel::getRelationId, LinkedHashMap::new, Collectors.toList()));
            List<Map.Entry<String, List<NoteModel>>> entries = map.entrySet().stream().toList();
            //分页
            int currIdx = (int) (page.getCurrent() > 1 ? (page.getCurrent() - 1) * page.getSize() : 0);
            List<MyNoteRelationVO> vos = new ArrayList<>();
            for (int i = 0; i < page.getSize() && i < entries.size() - currIdx; i++) {
                Map.Entry<String, List<NoteModel>> entry = entries.get(currIdx + i);
                MyNoteRelationVO myNoteVO = new MyNoteRelationVO();
                myNoteVO.setRelationId(entry.getKey());
                myNoteVO.setNoteNum(entry.getValue().size());
                NoteModel noteModel = entry.getValue().get(0);
                myNoteVO.setType(noteModel.getType());
                switch (noteModel.getType()) {
                    case chapter:
                        ChapterModel chapterModel = chapterService.getById(noteModel.getRelationId());
                        myNoteVO.setRelationName(chapterModel != null ? chapterModel.getName() : null);
                        myNoteVO.setParentId(chapterModel != null ? chapterModel.getParentId() : null);
                        myNoteVO.setId(chapterModel != null ? chapterModel.getId() : null);
                        break;
                    case paper:
                        PaperModel paperModel = paperService.getById(noteModel.getRelationId());
                        if (ObjectUtil.isNotEmpty(paperModel)) {
                            myNoteVO.setRelationName(paperModel != null ? paperModel.getName() : null);
                            myNoteVO.setLabel(paperModel != null && paperModel.getPaperType() == PaperType.trueTopic ? "全真" : "模拟");
                        } else {
                            PaperRecordsModel paperRecordsModel = paperRecordsService.getById(noteModel.getRelationId());
                            if (null != paperRecordsModel) {
                                PaperModel paperInfo = paperService.getPaperInfo(paperRecordsModel.getPaperId());
                                myNoteVO.setRelationName(paperInfo != null ? paperInfo.getName() : paperRecordsModel.getName());
                                if (paperInfo != null) {
                                    myNoteVO.setLabel(paperInfo.getPaperType().name());
                                } else {
                                    myNoteVO.setLabel(paperRecordsModel != null ? paperRecordsModel.getType().getDesc() : null);
                                }
                            }
                        }
                        break;
                }
                if (QuestionCollectionType.everyDayPractice == noteModel.getType()) {
                    EveryDayPracticeModel model = everyDayPracticeService.getById(noteModel.getRelationId());
                    if (ObjectUtil.isNotEmpty(model)) {
                        myNoteVO.setRelationName(model.getName());
                    }
                }
                vos.add(myNoteVO);
            }

            IPage<MyNoteRelationVO> myNoteVOIPage = new Page<>();
            myNoteVOIPage.setTotal(entries.size());
            if (QuestionCollectionType.chapter == type) {
                List<MyNoteRelationVO> allTree = coverChapterList(vos);
                myNoteVOIPage.setRecords(allTree);
            } else {
                myNoteVOIPage.setRecords(vos);
            }
            myNoteVOIPage.setSize(page.getSize());
            myNoteVOIPage.setCurrent(page.getCurrent());
            return myNoteVOIPage;
        }
    }

    List<MyNoteRelationVO> coverChapterList(List<MyNoteRelationVO> vos) {
        Map<String, MyNoteRelationVO> map = vos.stream().filter(m -> m.getId() != null).collect(Collectors.toMap(MyNoteRelationVO::getId, Function.identity()));
        return vos.stream().filter(f -> f.getId() != null).filter(vo -> "0".equals(vo.getParentId()) || !map.containsKey(vo.getParentId()))
                .map(m -> coverChildren(m, vos)).collect(Collectors.toList());
    }

    protected LambdaQueryWrapper<NoteModel> baseWrapper(NoteModel model, JSONObject otherParam) {
        if (null != model.getType() && model.getType().equals(QuestionCollectionType.rankCollect)) {
            String[] array = new String[]{"rankCollect", "hotQue"};
            return super.baseWrapper(
                    model.clearEmptyStringField("type"), otherParam).in(NoteModel::getRelationId, Arrays.asList(array));
        } else {
            return super.baseWrapper(model, otherParam);
        }

    }

    private MyNoteRelationVO coverChildren(MyNoteRelationVO pModel, List<MyNoteRelationVO> allList) {
        allList.stream().filter(a -> pModel.getId().equals(a.getParentId())).peek(m -> {
         /*   List<MyNoteRelationVO> children = pModel.getChildren();
            if (CollUtil.isEmpty(children)) {
                children = new ArrayList<>();
            }
            children.add(m);
            pModel.setChildren(children);*/

            int totalNum = pModel.getNoteNum() + m.getNoteNum();
            pModel.setNoteNum(totalNum);

            coverChildren(m, allList);
        }).collect(Collectors.toList());
        return pModel;
    }

    public List<String> getTreeIds(List<ChapterModel> allList, String parentId) {
        List<String> childrenIds = new ArrayList<>();
        allList.stream().filter(t -> parentId.equals(t.getParentId())).peek(m -> {
            childrenIds.add(m.getId());
            collectChildrenIds(m, allList, childrenIds);
        }).collect(Collectors.toList());
        childrenIds.add(parentId);
        return childrenIds;
    }

    private void collectChildrenIds(ChapterModel parent, List<ChapterModel> allList, List<String> childrenIds) {
        allList.stream().filter(t -> parent.getId().equals(t.getParentId())).peek(m -> {
            childrenIds.add(m.getId());
            collectChildrenIds(m, allList, childrenIds);
        }).collect(Collectors.toList());

    }

    @GetMapping("my-note-app")
    @Operation(summary = "我的笔记app")
    @Parameters({
            @Parameter(name = "type", description = "chapter章节,paper试卷, everyDayPractice每日一练,rankError高频错题"),
            @Parameter(name = "categoryId", description = "学科id")
    })
    public IPage<NoteModel> myNoteApp(@RequestParam QuestionCollectionType type, @ModelAttribute Page<NoteModel> page, @RequestParam String categoryId) {
        IPage<NoteModel> resPage = noteService.page(page, Wrappers.<NoteModel>lambdaQuery().eq(NoteModel::getType, type).eq(NoteModel::getCategoryId, categoryId));
        resPage.setRecords(listCover(resPage.getRecords(), null));
        return resPage;

    }

    @GetMapping("note-by-relation")
    @Operation(summary = "根据关联id找笔记")
    @Parameters({
            @Parameter(name = "relationId", description = "关联id"),
            @Parameter(name = "chapterFlag", description = "是否是章节"),
            @Parameter(name = "categoryId", description = "科目id")
    })
    public List<NoteModel> noteByRelation(@RequestParam String relationId, @RequestParam Boolean chapterFlag, @RequestParam String categoryId) {
        List<String> treeIds = new ArrayList<>();
        if (Boolean.TRUE.equals(chapterFlag)) {
            List<NoteModel> noteModels = noteService.selectList(Wrappers.<NoteModel>lambdaQuery().eq(BSDUAbsEntity::getCreatedBy, userContext.currentUserId())
                    .eq(NoteModel::getType, QuestionCollectionType.chapter));
            List<String> chapterIds = noteModels.stream().map(NoteModel::getRelationId).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(chapterIds)) {
                List<ChapterModel> chapterModels = chapterService.selectList(Wrappers.<ChapterModel>lambdaQuery().in(BaseEntity::getId, chapterIds));
                treeIds = getTreeIds(chapterModels, relationId);
                List<String> finalTreeIds = treeIds;
                return CollUtil.isNotEmpty(treeIds) ? noteModels.stream().peek(n -> {
                    QuestionModel questionModel = questionService.getById(n.getQuestionId());
                    n.setStem(null != questionModel ? questionModel.getStem() : null);
                }).filter(n -> finalTreeIds.contains(n.getRelationId())).collect(Collectors.toList()) : new ArrayList<NoteModel>();
            }
        }
        return noteService.selectList(Wrappers.<NoteModel>lambdaQuery()
                        .in(chapterFlag && CollUtil.isNotEmpty(treeIds), NoteModel::getRelationId, treeIds)
                        .eq(!chapterFlag, NoteModel::getRelationId, relationId)
                        .eq(NoteModel::getCategoryId, categoryId)
                )
                .parallelStream().peek(n -> {
                    QuestionModel questionModel = questionService.getById(n.getQuestionId());
                    if (null != questionModel) {
                        if (questionModel.getSourceType().equals(QuestionSourceType.combination)) {
                            n.setQuestionId(questionModel.getSourceId());
                        }
                        n.setStem(questionModel.getStem());
                    }

                }).collect(Collectors.toList());
    }

    @PutMapping("batch-verify")
    @Operation(summary = "批量审核")
    public Boolean batchVerify(@RequestParam List<String> ids, @RequestParam Integer status) {
        Integer integer = noteService.batchUpdate(null, Wrappers.<NoteModel>lambdaUpdate().in(NoteModel::getId, ids)
                .set(NoteModel::getVerify, status));
        return integer > 0;
    }

    @PutMapping("batch-delete")
    @Operation(summary = "批量删除")
    public Boolean batchDelete(@RequestParam List<String> ids) {
        Integer integer = noteService.batchUpdate(null, Wrappers.<NoteModel>lambdaUpdate().in(NoteModel::getId, ids)
                .set(BaseAbsEntity::getDeleted, true));
        return integer > 0;
    }

    @DeleteMapping("delete-by-chapter")
    @Operation(summary = "根据章节删除笔记")
    @Parameter(name = "chapterId", description = "章节id")
    public Boolean deleteByChapter(@RequestParam Long chapterId) {
        int delete = noteService.delete(Wrappers.<NoteModel>lambdaUpdate().eq(NoteModel::getType, QuestionCollectionType.chapter)
                .eq(NoteModel::getRelationId, chapterId.toString()));
        return delete > 0;
    }


    @DeleteMapping("delete-by-category")
    @Operation(summary = "根据科目删除笔记")
    @Parameter(name = "categoryId", description = "科目id")
    public Boolean deleteByCategory(@RequestParam String categoryId) {
        int delete = noteService.delete(Wrappers.<NoteModel>lambdaUpdate().eq(NoteModel::getCategoryId, categoryId));
        return delete > 0;
    }

    @GetMapping("get-note-list")
    @Operation(summary = "获取笔记列表")
    @Parameters({
            @Parameter(name = "relationId", required = false, description = "关联id，必传其一"),
            @Parameter(name = "questionId", required = false, description = "试题id，必传其一")
    })
    @Roles
    public IPage<MyNoteVO> getNoteList(@ModelAttribute Page<NoteModel> page, @RequestParam(required = false) String relationId, @RequestParam(required = false) String questionId) {
        //把自己的笔记排前面

        Page<MyNoteVO> resPage = new Page<>();
        IPage<NoteModel> notePage = noteService.pageList(page, userContext.currentUserId(), relationId, questionId, 1);
        List<MyNoteVO> myNoteVOS = notePage.getRecords().parallelStream().map(n -> {
            MyNoteVO myNoteVO = new MyNoteVO();
            BeanUtil.copyProperties(n, myNoteVO);
            IUserModel userDetail = userService.getUserDetail(n.getCreatedBy());
            myNoteVO.setCreateHeader(userDetail != null ? userDetail.getHeader() : diamondConfig.getUserDefaultHeader());
            myNoteVO.setCreateName(userDetail != null ? userDetail.getName() : "已注销");
            myNoteVO.setSex(userDetail != null ? userDetail.getSex() : null);
            return myNoteVO;
        }).toList();
        BeanUtil.copyProperties(notePage, resPage);
        resPage.setRecords(myNoteVOS);
        return resPage;

    }

    @Operation(summary = "获取笔记试题集合")
    @Parameters({
            @Parameter(name = "relationId", required = true, description = "关联id，必传其一"),
            @Parameter(name = "relationName", required = true, description = "关联类型"),
            @Parameter(name = "flag", required = false, description = "最新笔记")
    })
    @GetMapping("get-note-details")
    public Map<String, List<QuestionVo>> getNoteDetails(@RequestParam("relationId") String relationId, @RequestParam("relationName") QuestionCollectionType relationName, @RequestParam(value = "flag", defaultValue = "false") Boolean flag, @RequestParam(required = false) String categoryId) {
        return noteService.getNoteQuestionCollection(relationId, relationName, userContext.currentUserId(), flag, categoryId);
    }

    /**
     * 根据科目，获取可看笔记数量，包括自己的和别人公开的笔记
     */
    @GetMapping("get-note-num")
    public Long getNoteNum(@RequestParam(required = false) String categoryId) {
        QueryWrapper<NoteModel> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("category_id", categoryId)
                .and(wrapper -> wrapper.eq("open", 1)
                        .or()
                        .eq("created_by", userContext.currentUserId()));
        Long l = noteService.selectCount(queryWrapper);
        return l;
    }

    /**
     * 获取所有我的笔记
     */
    @GetMapping("get-note-list-my")
    public IPage<NoteModel> getMyNote(@RequestParam(required = true) String categoryId, @RequestParam(required = false, defaultValue = "true") Boolean my,@RequestParam(required = false) QuestionCollectionType type,@RequestParam(required = false,defaultValue = "1") Long current,@RequestParam(required = false,defaultValue = "10") Long pageSize) {
//        QueryWrapper<NoteModel> queryWrapper = new QueryWrapper<>();
//        if (my) {
//            queryWrapper.eq("category_id", categoryId)
//                    .eq("created_by", userContext.currentUserId())
//            ;
//        } else {
//            queryWrapper.eq("category_id", categoryId)
//                    .and(wrapper -> wrapper.eq("open", 1)
//                            .or()
//                            .eq("created_by", userContext.currentUserId()));
//        }
//        // 添加对 type 参数的筛选条件
//        if (type != null) {
//            queryWrapper.eq("type", type);
//        }
//
//        List<NoteModel> l = noteService.selectList(queryWrapper);
//
////        IPage<NoteModel> page = noteService.page(new Page<NoteModel>(current, pageSize), queryWrapper);


        Page<NoteModel> page = new Page<>(current, pageSize);
        if(my){
            return noteService.getNoteListMy(page, categoryId, userContext.currentUserId(), type);
        }else{
            return noteService.getNoteListMy(page, categoryId,null, type);
        }

//        return page;

    }
}
